/**
 * 绛惧��&楠�绛剧�?
 */
package com.fingard.dsp.bank.directbank.cib03.util;

import cfca.sadk.algorithm.common.Mechanism;
import cfca.sadk.lib.crypto.JCrypto;
import cfca.sadk.lib.crypto.Session;
import cfca.sadk.util.EncryptUtil;
import cfca.sadk.x509.certificate.X509Cert;
import com.alibaba.fastjson.JSONObject;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;



public class Signature {
	 public static final String ALGORITHM = "SHA1PRNG";
	  
	 public static final String ALGORITHM1 = "AES/ECB/PKCS5Padding";
    /**
     * ����绛惧��MAC瀛�绗�涓?
     * @param  params ���板��琛�锛�����mac���帮�?
     * @param  certName 璇�涔���绉�
     * @param  certPwd  璇�涔�瀵���
     * @return MAC瀛�绗�涓?
     */
    public static String generateMAC(Map<String, String> params, String certName, String certPwd) {

        if (params.containsKey("signType") && params.get("signType").equals("RSA")) {
            try {
        		// 璇诲��娴�璇�绉��ヨ��涔�锛���浜х��澧�锛��?�挎�㈡����浜х��ヨ��涔�
            	PrivateKey privKey = readPrivateKey(certName, certPwd);
                java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");

                signature.initSign(privKey);
                signature.update(generateParamStr(params).getBytes("UTF-8"));
                byte[] signed = signature.sign();

                // 璁＄��base64encode(signed)锛����㈣���濡���娉�浣跨��锛�璇疯��琛��挎��涓哄�跺��BASE64绫诲��?
                String mac = new sun.misc.BASE64Encoder().encode(signed)
                        .replaceAll(System.getProperty("line.separator"), "");

                return mac;
            } catch (Exception e) {
                // 璇诲��璇�涔�绛��洪�?
                return "SIGNATURE_RSA_CERT_ERROR";
            }
        } else {
        	// 绛惧��绫诲����璇�
            return "SIGNTYPE_ERROR";
        }
    }

    /**
     * 楠�璇����″�ㄨ�����淇℃��涓�绛惧����姝ｇ‘�?
     * @param params ���板��琛�锛�����mac���帮�?
     * @param certName 璇�涔���绉�
     * @return true-楠�绛鹃��杩�锛�false-楠�绛惧け璐�
     */
    public static boolean verifyMAC(Map<String, String> params, String certName) {

        if (!params.containsKey("mac")){
        	return false;
        }
        String mac = params.get("mac");
        if (params.containsKey("signType") && params.get("signType").equals("RSA")) {
            if (mac == null) {
            	return false;
            }
            try {
        		// 楠�璇�绛惧��锛�璇诲��娴�璇����ヨ��涔�锛���浜х��澧�锛����挎�㈡����浜у���ヨ��涔?
            	PublicKey pubKey = readPublicKey(certName);
                java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");

                signature.initVerify(pubKey);
                signature.update(generateParamStr(params).getBytes("UTF-8"));

                // 璁＄��base64decode(mac)��濡���娉�浣跨��锛�璇疯��琛��挎��涓哄�跺��BASE64绫诲��?
                byte[] bmac = new sun.misc.BASE64Decoder().decodeBuffer(mac);

                return signature.verify(bmac);
            } catch (Exception e) {
                return false;
            }
        } else {
        	return false;
        }
    }

    /**
     * �����ㄤ�MAC璁＄�������板��绗�涓层�?br>
     * @param params ���板��琛�锛�����mac���帮�?
     * @return 妯″�涓�key=value&key=value
     */
    private static String generateParamStr(Map<String, String> params) {
		// ��������绌哄��娈靛��瀹癸���mac浠ュ�锛�锛�濉��ュ��琛�
		List<String> paramList = new ArrayList<String>();
		for (String key : params.keySet()) {
			String val = params.get(key);
			// �ヤ负绌哄��娈靛��瀹癸���璺宠�涓���涓�����绛惧��
			if(val == null || val.equals("") || isVerify(key)){
				continue;
			}
			paramList.add(key + "=" + val);
		}

		// �叉��
		if (paramList.size() == 0) {
			return null;
		}
		// 瀵瑰��琛ㄨ�琛���搴?
		Collections.sort(paramList);
		// 浠?绗����叉�艰���瀛�绗�涓?
		StringBuilder sb = new StringBuilder();
		sb.append(paramList.get(0));
		for (int i = 1; i < paramList.size(); i++) {
			sb.append("&").append(paramList.get(i));
		}
		System.out.println("��涓�绛惧����缁������颁负:" + sb.toString());
		return sb.toString();
	}

    /**
	 * isVerify:(璇锋�瀛�娈靛���版�����?���涓�绛惧��).
	 *
	 * @author fanweitao
	 * @date 2017骞?�?9�?涓���4:58:02
	 * @param key
	 * @since JDK 1.6
	 */
	private static boolean isVerify(String key) {
		if ("mac".equals(key) 
				|| "priKeyName".equals(key)
				|| "priKeyPwd".equals(key)) {
			return true;
		}
		return false;
	}
	
    /**
     * 璇诲��PFX��浠朵腑�����风��ワ�瀹���浣跨�ㄤ腑��缂�瀛�璇ュ�芥�拌����?
     * @param certPath    璇�涔���浠惰矾寰�
     * @param password    瀵���
     * @return 绉���
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws IOException
     * @throws UnrecoverableKeyException
     */
    private static PrivateKey readPrivateKey(String certPath, String password)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
            IOException, UnrecoverableKeyException {

        KeyStore keyStore = KeyStore.getInstance("pkcs12");
        InputStream is = null;

        File file = new File(certPath);
        if (file.exists()) {
            is = new FileInputStream(certPath);
        } else {
            Class<? extends Signature> clz = Signature.class;
            ClassLoader cl = clz.getClassLoader();

            URL url = cl.getResource(certPath);
            if (url == null) throw new FileNotFoundException();

            is = cl.getResourceAsStream(certPath);
        }
        keyStore.load(is, password == null ? null : password.toCharArray());
        if (is != null) is.close();

        return (PrivateKey) keyStore.getKey(keyStore.aliases().nextElement(), password == null ? null : password.toCharArray());
    }

    /**
     * 璇诲��CRT��浠朵腑���惰����ワ�瀹���浣跨�ㄤ腑��缂�瀛�璇ュ�芥�拌����?
     * @param certPath    璇�涔���浠惰矾寰�
     * @return ����
     * @throws CertificateException
     * @throws IOException
     */
    private static PublicKey readPublicKey(String certPath)
            throws CertificateException, IOException {

        File file = new File(certPath);
        InputStream is = null;
        try {
            if (file.exists()) {
                is = new FileInputStream(certPath);
            } else {
                Class<? extends Signature> clz = Signature.class;
                ClassLoader cl = clz.getClassLoader();

                URL url = cl.getResource(certPath);
                if (url == null) throw new FileNotFoundException();

                is = cl.getResourceAsStream(certPath);
            }
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
            if (is != null) is.close();
            return cert.getPublicKey();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    public static Map<String, String> jsonToMap(String jsonStr) {
    	Map<String, String> map = new HashMap<String, String>();
		JSONObject json = JSONObject.parseObject(jsonStr);
		Iterator<String> keys = json.keySet().iterator();
		while (keys.hasNext()) {
			String key = (String) keys.next();
			String value = null == json.get(key)? null:json.get(key).toString();
			map.put(key, value);
		}
		return map;
    }
	
	/**
	 * 缁�����淇℃����瀵?
	 * @param msgContent ����
	 * @param certName 璇�涔���绉�
	 * @return 瀵���
	 * @throws Exception
	 */
	public static String encryptByCFCA(String msgContent, String certName) throws IOException {
        InputStream fis = null;
		try {
			final String deviceName = JCrypto.JSOFT_LIB;
			JCrypto.getInstance().initialize(deviceName, null);
			Session session = JCrypto.getInstance().openSession(deviceName);
			final String c12FileText = certName;

			File file = new File(c12FileText);
			if (file.exists()) {
				fis = new FileInputStream(c12FileText);
			} else {
				Class<? extends Signature> clz = Signature.class;
				ClassLoader cl = clz.getClassLoader();
				
				URL url = cl.getResource(c12FileText);
				if (url == null)
					throw new FileNotFoundException();
				
				fis = cl.getResourceAsStream(c12FileText);
			}
			// ��瀵�绠�娉�锛?RSA/ECB/PKCS1PADDING"
			final Mechanism mechanism = new Mechanism(Mechanism.RSA_PKCS);
			X509Cert cert = new X509Cert(fis);
			// RSA���ュ��瀵�锛��垮害�?甯搁��瀹�锛�1024瀵��ヤ�?17瀛�����锛�2048瀵��ヤ�?45瀛�����锛�
			byte[] base64Bytes = EncryptUtil.encrypt(mechanism, cert.getPublicKey(), msgContent.getBytes("UTF8"), session);
			//System.err.println(" demoRSAEncryptMessage: " + new String(base64Bytes));
			return new String(base64Bytes);
		} catch (Exception e) {
			return null;
		}finally {
		    if (fis != null) {
		        fis.close();
            }
        }
	}
	
	/**
	 * 缁�����淇℃��瑙ｅ�?
	 * @param msgContent 瀵���
	 * @param certName 璇�涔���绉�
	 * @param certPwd 璇�涔�瀵���
	 * @return String ����
	 * @throws Exception
	 */
	public static String decoderByCFCA(String msgContent, String certName, String certPwd) {
		try {
			if(msgContent == null || "".equals(msgContent.trim())){
				return "";
			}
			//娴�璇���澧�锛�璇诲��姹��朵�娴�璇���澧�绉��ヨ��涔�
			PrivateKey privateKey = readPrivateKey(certName, certPwd);
			final String deviceName = JCrypto.JSOFT_LIB;
			JCrypto.getInstance().initialize(deviceName, null);
			Session session = JCrypto.getInstance().openSession(deviceName);
			// ��瀵�绠�娉�锛?RSA/ECB/PKCS1PADDING"
			final Mechanism mechanism = new Mechanism(Mechanism.RSA_PKCS);
			PrivateKey priKey = privateKey;
			// RSA绉��ヨВ瀵�锛��垮害�?甯搁��瀹�锛�1024瀵��ヤ�?28瀛���锛?048瀵��ヤ�?56瀛���锛?
			byte[] decryptText = EncryptUtil.decrypt(mechanism, priKey, msgContent.getBytes("UTF-8"), session);
			return new String(decryptText, "UTF8");
		} catch (Exception e) {
			return null;
		}
		
	}
	
	/**
	 * 
	 * AESDecode:(��AES缁���瀹硅В瀵?.
	 *
	 * @author luhuixian
	 * @date 2018骞?�?0�?涓���12:45:39
	 * @param str
	 * @param num
	 * @return
	 * @throws Exception
	 * @since JDK 1.6
	 */
	 public static byte[] AESDecode(String str,String num) throws Exception{
		  
		  KeyGenerator kg = KeyGenerator.getInstance("AES");
		  
		  SecureRandom sr = SecureRandom.getInstance(ALGORITHM);
		  
		  sr.setSeed(num.getBytes());
		  
		  
		  kg.init(128, sr);
		  
		  SecretKey sk = kg.generateKey();

		  byte[] raw = sk.getEncoded();
		  SecretKey key = new SecretKeySpec(raw,"AES");
		  
		  Cipher cipher = Cipher.getInstance(ALGORITHM1);
		  cipher.init(Cipher.DECRYPT_MODE, key);
		  byte[] str_AES = cipher.doFinal(hex2byte(str));
		  return str_AES;
	  }
	 
	  public static byte[] hex2byte(String str){
		  if(isNull(str)){
			  return null;
		  }
		  str = str.trim();
		  int len = str.length();
		  byte[] b = new byte[len / 2];
		  for(int i=0;i<str.length();i+=2){
			  b[i / 2] = (byte) Integer.decode("0x"+str.substring(i,i+2)).intValue();
		  }
		  return b;
	  }
	  
	  public static boolean isNull(String str) {
			return (str == null || (str.trim().length() == 0)) ? true : false;
		}
}
